import CryptoJS from 'crypto-js'; // 引入加密库
// 同步储存 
export const Storage = {
	install(Vue, options) {
		const secretKey = options.secretKey || 'your_secret_key'; // 设置加密密钥
		const prefix = options.prefix || 'your_prefix_'; // 设置存储前缀

		/**
		 * 加密数据
		 * @param {any} data 需要加密的数据
		 * @returns {string} 返回加密后的字符串
		 */
		const encrypt = (data, key = secretKey) => {
			const ciphertext = CryptoJS.AES.encrypt(JSON.stringify(data), key).toString();
			return ciphertext;
		};

		/**
		 * 解密数据
		 * @param {string} ciphertext 加密后的字符串
		 * @returns {any} 返回解密后的数据
		 */
		const decrypt = (ciphertext, key = secretKey) => {
			const bytes = CryptoJS.AES.decrypt(ciphertext, key);
			if (!bytes) {
				console.log('解密失败：bytes 为空');
				return null; // 返回空值或其他错误处理方式
			} else {
				const plaintext = bytes.toString(CryptoJS.enc.Utf8);
				console.log('解密结果：', plaintext);
				const data = JSON.parse(plaintext);
				return data;
			}
		};

		/**
		 * 设置本地存储数据
		 * @param {string} key 存储的键名
		 * @param {any} value 存储的值
		 * @param {number} expireTime 过期时间（单位：毫秒），可选参数 24 * 60 * 60 * 1000; // 过期时间为一天
		 */
		const setStorage = (key, value, expireTime) => {
			const currentTime = new Date().getTime();
			const expireAt = expireTime ? currentTime + expireTime : 0;
			// const data = value;
			const data = {
				value: encrypt(value, key), // 加密存储的数据
				expireAt,
			};
			uni.setStorageSync(prefix + key, JSON.stringify(data));
		};

		/**
		 * 获取本地存储数据
		 * @param {string} key 存储的键名
		 * @returns {any} 返回存储的值，如果过期或不存在则返回null
		 */
		const getStorage = (key) => {
			const data = uni.getStorageSync(prefix + key);
			if (data) {
				const {
					value,
					expireAt
				} = JSON.parse(data);
				/* const value = JSON.parse(data);
				return value; */
				if (expireAt === 0 || new Date().getTime() < expireAt) {
					return decrypt(value, key); // 解密获取到的数据
				} else {
					removeStorage(key); // 超过时间限制，清除数据
					return null;
				}
			} else {
				return null;
			}
		};

		/**
		 * 删除本地存储数据
		 * @param {string} key 存储的键名
		 */
		const removeStorage = (key) => {
			uni.removeStorageSync(prefix + key);
		};
		/**
		 * @typedef {Object} Storage
		 * @property {(key: string, value: any) => void} set - 设置存储值
		 * @property {(key: string) => any} get - 获取存储值
		 * @property {(key: string) => void} remove - 移除存储值
		 */

		// 为 Vue.prototype.$storage 添加类型注释
		/** 
		 * @type {Storage}
		 */
		Vue.prototype.$storage = {
			set: setStorage,
			get: getStorage,
			remove: removeStorage
		};
		Vue.prototype.$crypt = {
			set: encrypt,
			get: decrypt
		};
	}
};
// 路由记录 // 定义一个名为 RouterRecord 的对象，该对象是一个 Vue 插件
export const RouterRecord = {
	install(Vue, options) {
		// 获取插件配置项中的 key 值，默认为 "router-record"
		const key = options.key || 'router-record';
		// 获取 Vue 实例中的 storage 对象
		const storage = Vue.prototype.$storage;

		// 定义记录路由历史的类
		class Record {
			constructor() {
				// 保存当前路由路径
				this.currentRoute = this.getCurrentRoute();
				// 从本地缓存中获取路由历史记录
				this.recordAry = storage.get(key) || [];
			}
			// 获取当前路由
			getCurrentRoute() {
				const pages = getCurrentPages();
				if (pages.length > 0) {
					const currentPage = pages[pages.length - 1];
					return currentPage.route;
				}
				return '';
			}
			// 更新路由历史记录数组并将其存入本地缓存
			upRecordAry(ary) {
				// 将路由历史记录存入本地缓存
				storage.set(key, ary);
				// 更新路由历史记录数组
				this.recordAry = ary;
			}

			// 处理跳转路由的方法
			handler(data, callBack) {
				this.currentRoute = this.getCurrentRoute();
				const {
					url
				} = data;
				// 如果跳转的路由地址不存在，则抛出错误
				if (url === undefined) {
					throw `url:${url}`;
				} else {
					// 否则执行回调函数
					callBack(url);
				}
			}
			// 导航到新页面或 tabBar 页面，并将新的路由信息添加到路由历史记录中
			navigateToOrSwitchTabWithRecord(data, key) {
				const flag = data.flag; // 不保存当前的路由
				this.handler(data, url => {
					// 如果上一次跳转使用了 lastKey，则直接返回上一页 
					if (flag || this.cleanRoute(this.currentRoute) === this.cleanRoute(this
							.recordAry.slice(-1)[0])) {
						// 将新的路由信息添加到路由历史记录中
						this.upRecordAry(this.recordAry.concat(url));
					} else {
						// 将新的路由信息添加到路由历史记录中
						this.upRecordAry(this.recordAry.concat(this.currentRoute, url));
					}
					uni[key](data);
				});
			}
			// 导航到新页面，并将新的路由信息添加到路由历史记录中
			navigateTo(data) {
				this.navigateToOrSwitchTabWithRecord(data, 'navigateTo');
			}

			// 跳转到 tabBar 页面，并将新的路由信息添加到路由历史记录中
			switchTab(data) {
				let str = 'switchTab';
				const ary = storage.get(key + str) || [];
				storage.set(key + str, Array.from(new Set([...ary, data.url])));
				this.navigateToOrSwitchTabWithRecord(data, str);
			}
			// 跳转到新页面，会关闭当前页面，并将新的路由信息替换掉当前路由历史记录中最后一个路由信息
			redirectTo(data) {
				this.handler(data, url => {
					const {
						success,
						...obj
					} = data;
					// 跳转到新页面
					uni.redirectTo({
						...obj,
						success: (res) => {
							success(res);
							// 更新路由历史记录数组
							this.upRecordAry(this.recordAry.concat(url));
						}
					});

				});
			}

			// 关闭所有页面并跳转到应用程序的某个页面
			reLaunch(data, ary = []) {
				this.handler(data, url => {
					const {
						success,
						...obj
					} = data;
					// 更新路由历史记录数组
					this.upRecordAry([url]);
					// 关闭所有页面并跳转到应用程序的某个页面
					uni.reLaunch({
						...obj,
						success: (res) => {
							success(res);
							this.reopenPage(ary);
						}
					});
				});
			}

			// 返回到上一个页面或多个页面
			navigateBack(delta = 1) {
				// 如果是在 H5 环境下，则使用浏览器的后退功能返回上一页
				if (process.env.UNI_PLATFORM === 'h5') {
					window.history.back();
				} else {
					// 否则使用 uni-app 提供的 navigateBack 方法返回上一页
					uni.navigateBack({
						delta
					});
				}
			}


			// 清除路由历史记录
			clearCurrentRecord() {
				this.upRecordAry(this.recordAry.slice(0, -1));
			}

			/**
			 * 重新打开页面函数，逐个重新打开页面
			 * @param {Array} recordAry 路由历史记录数组
			 * @param {string} currentRoute 当前页面路由路径
			 */
			reopenPage(recordAry, currentRoute) {
				// 获取需要切换 Tab 的页面列表
				const switchTabPages = uni.getStorageSync(key + 'switchTab') || [];
				// 定义递增函数来处理页面打开操作
				const openPage = (index) => {
					if (index >= recordAry.length) {
						return;
					}
					const url = recordAry[index];
					// 如果当前路由路径不在本次循环中，则重新打开页面
					if (!currentRoute || currentRoute !== this.cleanRoute(url)) {
						// 使用延迟执行的方式重新打开页面，以避免在同一个事件循环中导致页面渲染问题
						const navType = switchTabPages.includes(url) ? 'switchTab' :
							'navigateTo';
						// 根据页面是否需要切换 Tab 来选择导航方式
						uni[navType]({
							url,
							complete: () => {
								openPage(index + 1); // 递增调用打开下一个页面
							}
						});
					} else {
						openPage(index + 1); // 直接递增调用打开下一个页面
					}
				}
				openPage(0); // 调用递增函数开始打开页面
			}

			/**
			 * 重新打开之前的页面
			 * @param {string} token 访问令牌
			 * @param {Array} exemptedRoutes 免除认证的页面路由列表
			 */
			reopenPreviousPages(token, exemptedRoutes = []) {
				// 从本地缓存中获取路由历史记录
				const recordAry = storage.get(key) || [];

				// 获取当前路由路径和最后一个历史记录路径
				const currentRoute = this.getCurrentRoute();
				const lastRoute = recordAry[recordAry.length - 1] || currentRoute;

				// 清理路由路径中的斜杠
				const cleanedCurrentRoute = this.cleanRoute(currentRoute);
				const cleanedLastRoute = this.cleanRoute(lastRoute);

				// 如果当前路由路径和最后一个历史记录路径相同，则不需要重新打开页面
				if (cleanedCurrentRoute === cleanedLastRoute) {
					return 'Current route is the same as the last route';
				}

				// 检查当前页面是否在免除认证的页面列表中
				const isExemptedRoute = exemptedRoutes.includes(cleanedCurrentRoute);

				// 如果当前页面需要认证且用户未登录，则跳转到登录页面 
				if (!isExemptedRoute && !token) {
					return '请完善没有登录跳转到登录界面还是指定的界面';
				}

				// 重新打开页面
				this.reopenPage(recordAry, currentRoute);
			}

			/**
			 * 清理路由路径中的斜杠
			 * @param {string} route 路由路径
			 * @returns {string} 清理后的路由路径
			 */
			cleanRoute(route) {
				if (!route || route === true) return ''
				return (route.startsWith("/") ? route.substring(1) : route).split('?')[0];
			}
		}

		// 在 Vue 实例中添加 $record 对象，可以通过 this.$record 访问路由历史记录功能
		Vue.prototype.$record = new Record();

	},
};
// 创建一个 Vue 实例作为事件总线
export const MyPlugin = {
	install(Vue) {
		// 创建一个 Vue 实例作为事件总线
		const bus = new Vue();
		// 用于存储事件和对应的订阅回调
		const eventMap = {};

		Vue.prototype.$eventBus = {
			// 发布事件
			emit(event, ...args) {
				bus.$emit(event, ...args);
			},
			// 订阅事件，现在可以接受一个事件数组
			on(events, callback) {
				if (Array.isArray(events)) {
					events.forEach((event) => {
						this.subscribe(event, (...args) => {
							callback(event, ...args); // 将事件名称作为第一个参数传递给回调函数
						});
					});
				} else {
					this.subscribe(events, (...args) => {
						callback(...args);
					});
				}
			},
			// 辅助方法，用于订阅单个事件
			subscribe(event, callback) {
				// 要先执行回调要不然不触发
				bus.$on(event, (...args) => {
					callback(...args)
				});
				if (!eventMap[event]) {
					eventMap[event] = [];
				}
				eventMap[event].push(callback);

			},
			// 取消订阅事件，现在也可以接受一个事件数组
			clear(events) {
				if (Array.isArray(events)) {
					events.forEach((event) => {
						this.unsubscribe(event);
					});
				} else {
					this.unsubscribe(events);
				}
			},
			// 辅助方法，用于取消订阅单个事件
			unsubscribe(event) {
				if (eventMap[event]) {
					eventMap[event].forEach(callback => {
						bus.$off(event, callback);
					});
					delete eventMap[event];
				}
			}
		};
	}
};